/**
 * 
 */
package br.com.beyondclick.model.entity;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

/**
 * @author AC de Souza
 */
@Entity
public class PedidoMaterial implements Serializable, Comparable<PedidoMaterial> {

	private static final long serialVersionUID = 1L;

	@Id @GeneratedValue
	private Long id;

	@ManyToOne(optional=false)
	private Pedido pedido;

	@ManyToOne(optional=false)
	private Material material;
	private long quantidade;

	private BigDecimal precoCompra;
	private BigDecimal precoVenda;

	@OneToMany(mappedBy="pedidoMaterial", cascade=CascadeType.ALL)
	private List<CompraPedidoMaterial> compraPedidoMateriais;

	/** = new BigDecimal(BigInteger.ZERO, 2)
	 * @param quantidade
	 * @param precoVenda
	 * @param pedido
	 * @param material
	 */
	public PedidoMaterial(long quantidade, BigDecimal preco, Pedido pedido, Material material) {
		this();
		this.quantidade = quantidade;
		this.precoVenda = preco;
		this.pedido = pedido;
		this.material = material;
	}

	public PedidoMaterial() {
		precoVenda = new BigDecimal(BigInteger.ZERO, 2);
		precoCompra = new BigDecimal(BigInteger.ZERO, 2);
	}

	/**
	 * Usado pela tela de cadastro de Pedido.
	 * Quando adicionado o mesmo {@link Material}, no {@link Pedido}, ao inv�s de criar mais um {@link PedidoMaterial}
	 * a quantidade, a ser adicionada, ser� somada a quantidade j� pedida.
	 *   
	 * @param quantidade Quantidade a ser adicionada, � quantidade j� pedida.
	 * @return Quantidade total pedida.
	 */
	public long addQuantidade(long quantidade) {
		this.quantidade += quantidade;
		return this.quantidade;
	}

	/**
	 * Calcular quantos items {@link Material} faltam ser comprados.
	 * O c�lculo � feito subtraindo a quantidade pedida da {@link #getQuantidadeComprada()}.
	 * 
	 * @return Quantidade de {@link Material} pendente de compra.
	 */
	public long getQuantidadePendente() {
		return this.quantidade - getQuantidadeComprada();
	}

	/**
	 * Soma das quantidades compradas em todas as {@link Compra} deste {@link PedidoMaterial}
	 * 
	 * @return Quantos item {@link Material} j� foram comprados.
	 */
	@Transient
	private Long quantidadeComprada = null;
	public long getQuantidadeComprada() {
		if( quantidadeComprada == null ){
			quantidadeComprada = 0L;
			if( compraPedidoMateriais != null ){
				for (CompraPedidoMaterial compraPedidoMaterial : compraPedidoMateriais) {
					quantidadeComprada += compraPedidoMaterial.getQuantidade();
		        }
			}
		}

		return quantidadeComprada;
	}

	/**
	 * Adiciona os dados da nova compra de materiais e recalcula o precoCompra.
	 * 
	 * @param precoCompra Pre�o da compra atual.
	 * @param quantidadeCompra Quantidade comprada, na compra atual.
	 * @return Quantidade de {@link Material} atendida, incluido a compra adicionada. 
	 */
	public long addCompraPedidoMaterial(final BigDecimal precoCompra, final long quantidadeCompra) {
		if( this.precoCompra == null ) this.precoCompra = new BigDecimal(BigInteger.ZERO, 2); 

		long totalQuantidade = getQuantidadeComprada() + quantidadeCompra;

		BigDecimal precoAtual = this.precoCompra.multiply( BigDecimal.valueOf(getQuantidadeComprada()) );
		BigDecimal precoComprado = precoCompra.multiply( BigDecimal.valueOf(quantidadeCompra) );
		BigDecimal precoTotal = precoAtual.add(precoComprado);

		BigDecimal precoUnitarioAtual = precoTotal.divide(BigDecimal.valueOf(totalQuantidade), RoundingMode.HALF_UP);

		this.quantidadeComprada += quantidadeCompra;
		this.precoCompra = precoUnitarioAtual;
		return this.getQuantidadeComprada();
	}
	
	/**FIXME Retirei a Compra daqui. Para recuperar seus dados, v� por {@link #compraPedidoMateriais}
	 * 
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	public int compareTo(PedidoMaterial o) {
		if(this.pedido.getOrgao().getNome().equals(o.pedido.getOrgao().getNome())){
			/*
			if(this.compra.getFornecedor().equals(o.compra.getFornecedor())){
				return this.material.getNome().compareTo(o.material.getNome());
			}else{
				return this.compra.getFornecedor().compareTo(o.compra.getFornecedor());
			}
			*/
			return 0;
		}else{
			return this.pedido.getOrgao().getNome().compareTo(o.pedido.getOrgao().getNome());
		}
	}

	/**
	 * Calcular o valor de compra do meterial, baseado na m�dia ponderada das compras.
	 * @return the precoCompra
	 */
	public BigDecimal getPrecoCompra() {
		BigDecimal mediaPonderadaValoresCompra = new BigDecimal(BigInteger.ZERO, 2);
		if( compraPedidoMateriais == null || compraPedidoMateriais.isEmpty() ) return mediaPonderadaValoresCompra;

		BigDecimal totalValoresCompra = new BigDecimal(BigInteger.ZERO, 2);
		long totalPesos = 0l;
		for (CompraPedidoMaterial compraPedidoMaterial : compraPedidoMateriais) {
			totalValoresCompra = totalValoresCompra.add(compraPedidoMaterial.getPrecoTotalCompra());
			totalPesos += compraPedidoMaterial.getQuantidade();
		}
		mediaPonderadaValoresCompra = totalValoresCompra.divide( BigDecimal.valueOf(totalPesos) );
		
		return mediaPonderadaValoresCompra;
	}
	
	public BigDecimal getTotal(){
		BigDecimal totalItemPedido = new BigDecimal(BigInteger.ZERO, 2);
		totalItemPedido = getPrecoVenda().multiply( BigDecimal.valueOf(getQuantidade()) );

		return totalItemPedido != null ? totalItemPedido : new BigDecimal(BigInteger.ZERO, 2);
	}

	public double getComissaoVendedor(){
		try{
			return this.precoVenda.doubleValue() * pedido.getPercentual() / 100;
		}catch(NullPointerException e){
			return 0;
		}
	}

	/**
	 * Diferen�a entre o {@link #precoCompra} do {@link #precoVenda}
	 * 
	 * @return Lucro da venda.
	 */
	public BigDecimal getLucro(){
		return this.precoVenda.subtract(this.precoCompra);
	}

	/**
	 * @return the compraPedidoMateriais
	 */
	public List<CompraPedidoMaterial> getCompraPedidoMateriais() {
		return compraPedidoMateriais;
	}

	/**
	 * @param compraPedidoMateriais the compraPedidoMateriais to set
	 */
	public void setCompraPedidoMateriais(
			List<CompraPedidoMaterial> compraPedidoMateriais) {
		this.compraPedidoMateriais = compraPedidoMateriais;
	}


    /**
     * @return the id
     */
    public Long getId() {
    	return id;
    }
    /**
     * @param id the id to set
     */
    public void setId(Long id) {
    	this.id = id;
    }

	
    /**
     * @return the material
     */
    public Material getMaterial() {
    	return material;
    }

	
    /**
     * @param material the material to set
     */
    public void setMaterial(Material material) {
    	this.material = material;
    }

	
    /**
     * @return the pedido
     */
    public Pedido getPedido() {
    	return pedido;
    }

	
    /**
     * @param pedido the pedido to set
     */
    public void setPedido(Pedido pedido) {
    	this.pedido = pedido;
    }

	
    /**
     * @return the precoVenda
     */
    public BigDecimal getPrecoVenda() {
    	return precoVenda;
    }

	
    /**
     * @param precoVenda the precoVenda to set
     */
    public void setPrecoVenda(BigDecimal precoVenda) {
    	this.precoVenda = precoVenda;
    }

	
    /**
     * @return the quantidade
     */
    public long getQuantidade() {
    	return quantidade;
    }

	
    /**
     * @param quantidade the quantidade to set
     */
    public void setQuantidade(long quantidade) {
    	this.quantidade = quantidade;
    }

	/**
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int PRIME = 31;
		int result = 1;
		result = PRIME * result + ((material == null) ? 0 : material.hashCode());
		result = PRIME * result + ((pedido == null) ? 0 : pedido.hashCode());
		return result;
	}

	/**
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final PedidoMaterial other = (PedidoMaterial) obj;
		if (material == null) {
			if (other.material != null)
				return false;
		} else if (!material.equals(other.material))
			return false;
		if (pedido == null) {
			if (other.pedido != null)
				return false;
		} else if (!pedido.equals(other.pedido))
			return false;
		return true;
	}
}